package org.netty.message.gper.handler;

import org.netty.message.gper.entity.GpHeader;
import org.netty.message.gper.entity.GpMessageRecord;
import org.netty.message.gper.entity.HeaderData;
import org.netty.message.gper.enumReq.EnumReq;

import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundHandlerAdapter;
import io.netty.handler.timeout.IdleStateEvent;
import lombok.extern.slf4j.Slf4j;

@Slf4j
public abstract class AbstractGpHandler extends ChannelInboundHandlerAdapter {

	private String name;

	public AbstractGpHandler(String name) {
		this.name = name;
	}

	protected abstract void handlerData(ChannelHandlerContext ctx, Object obj) throws Exception;

	/**
	 * 无论是客户端还是服务端都需要调用channelRead， 然后根据不同的报文的类型选择不同的处理逻辑
	 */
	@Override
	public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
		// TODO Auto-generated method stub
		GpMessageRecord gpMessageRecord = (GpMessageRecord) msg;
		// 获取请求类型
		byte reqType = ((GpMessageRecord) msg).getHeader().getHeaderData().getReqType();
		switch (reqType) {
		case (byte) 0:
			// 如果是请求报文，服务端就要去处理接收数据并发送回复报文
			handlerData(ctx, msg);
			break;
		case (byte) 1:
			// 如果是回复报文，那么就是服务端发送给客户端的，打印就行
			log.info("receive message:" + gpMessageRecord);
			break;
		case (byte) 2:
			// 如果是客户端发送的ping报文，回复pong报文
			sendPongMsg(ctx);
			break;
		case (byte) 3:
			// 如果收到的是服务端的pong报文，不做处理
			log.info(name + " get  pong  msg  from" + ctx.channel().remoteAddress());
			break;
		default:
			break;
		}
		super.channelRead(ctx, msg);
	}

	/**
	 * 心跳检测会调用该方法，如果你没有读写会触发此方法，从而拿到事件的类型
	 **/
	@Override
	public void userEventTriggered(ChannelHandlerContext ctx, Object evt) throws Exception {
		// TODO Auto-generated method stub
		IdleStateEvent stateEvent = (IdleStateEvent) evt;
		switch (stateEvent.state()) {
		// 如果没有读
		case READER_IDLE:
			handlerReaderIdle(ctx);
			break;
		// 如果没有写
		case WRITER_IDLE:
			handlerWriterIdle(ctx);
			break;
		// 既没有读也没有写
		case ALL_IDLE:
			handlerAllIdle(ctx);
			break;
		default:
			break;
		}
		super.userEventTriggered(ctx, evt);
	}

	protected void handlerAllIdle(ChannelHandlerContext ctx) {
		log.info(name + "没有读也没有写，触发AllIdle事件===================");
	}

	/**
	 * @param ctx
	 */
	protected void handlerWriterIdle(ChannelHandlerContext ctx) {
		log.info(name + "没有写，触发WriterIdle事件===================");
	}

	/**
	 * 如果没有读
	 */
	protected void handlerReaderIdle(ChannelHandlerContext ctx) {
		log.info(name + "没有读，触发ReaderIdle事件===================");
	}

	protected void sendPingMsg(ChannelHandlerContext ctx) {
		GpMessageRecord gpMessageRecord = createObject(EnumReq.PING.code());
		ctx.writeAndFlush(gpMessageRecord);
		log.info(name + "发送ping包：" + ctx.channel().remoteAddress());
	}

	protected void sendPongMsg(ChannelHandlerContext ctx) {
		GpMessageRecord gpMessageRecord = createObject(EnumReq.PONG.code());
		ctx.writeAndFlush(gpMessageRecord);
		log.info(name + "发送pong包：" + ctx.channel().remoteAddress());

	}

	protected GpMessageRecord createObject(byte reqType) {
		GpMessageRecord gpMessageRecord = new GpMessageRecord();
		GpHeader gpHeader = new GpHeader();
		HeaderData headerData = new HeaderData();
		gpMessageRecord.setHeader(gpHeader);
		gpHeader.setHeaderData(headerData);
		headerData.setReqType(reqType);
		return gpMessageRecord;
	}
}
